package com.golxen.framework.PBPacket;


import com.golxen.utils.LogUtil;
import com.google.protobuf.Message;
import io.netty.buffer.ByteBuf;

import java.nio.ByteBuffer;

public class PBPacket {

	public static final short HDR_SIZE = 18;
	public static final short HEADER = 0x17ab;

	private short header = HEADER;
	private int len;
	private int code;
	private long playerId;

	private int byteLength;
	private byte[] bytes;

	private Message message; // Proto

	private byte opCode = 0x2;
	private Object myMsg;

	public PBPacket() {

	}

	public PBPacket(Object myMsg) {
		this.myMsg = myMsg;
	}

	public PBPacket(int code, byte[] bytes) {
		this(code, -1);
		this.bytes = bytes;
	}

	public PBPacket(int code) {
		this(code, -1);
	}

	public PBPacket(int code, long playerId) {
		this.code = code;
		this.playerId = playerId;
	}

	public PBPacket(int code, Object myMsg) {
		this.code = code;
		this.myMsg = myMsg;
	}

	public PBPacket(int code, int playerId, Object myMsg) {
		this.code = code;
		this.playerId = playerId;
		this.myMsg = myMsg;
	}

	public short getHeader() {
		return header;
	}

	public int getLen() {
		return len;
	}

	public void setLen(int len) {
		this.len = len;
	}

	public int getCode() {
		return code;
	}

	public void setCode(int code) {
		this.code = code;
	}

	public long getPlayerId() {
		return playerId;
	}

	public void setPlayerId(long playerId) {
		this.playerId = playerId;
	}

	public byte[] getBytes() {
		return bytes;
	}

	public void setBytes(byte[] bytes) {
		this.bytes = bytes;
	}

	public Message getMessage() {
		return message;
	}

	public void setMessage(Message message) {
		this.message = message;
	}

	public void readHeader(ByteBuffer in) {
		in.getShort();
		len = in.getInt();
		code = in.getInt();
		playerId = in.getLong();
	}

	public void readHeaderNetty(ByteBuf in) {
		in.readShort();
		len = in.readInt();
		code = in.readInt();
		playerId = in.readLong();
	}

	public void read(ByteBuf in) {
		in.readShort();
		len = in.readInt();
		code = in.readInt();
		playerId = in.readLong();

		bytes = new byte[in.capacity() - HDR_SIZE];
		in.readBytes(bytes);
	}

	public void writeHeader(int len, ByteBuffer out) {
		out.putShort(HEADER);
		out.putInt(len);
		out.putInt(code);
		out.putLong(playerId);
	}

	public void writeHeader(int len, ByteBuf out) {
		out.writeShort(HEADER);
		out.writeInt(len);
		out.writeInt(code);
		out.writeLong(playerId);
		if (message != null) {
			out.writeBytes(message.toByteArray());
		} else if (bytes != null) {
			if (byteLength != 0) {
				out.writeBytes(bytes, 0, byteLength);
			} else {
				out.writeBytes(bytes);
			}
		}
	}

	public void writeHeaderByte(int len, ByteBuf out) {
		out.writeShort(HEADER);
		out.writeInt(len);
		out.writeInt(code);
		out.writeLong(playerId);
		if (bytes != null) {
			out.writeBytes(bytes);
		}
	}

	public void writeHeartbeat(int len, ByteBuf out) {
		out.writeShort(HEADER);
		out.writeInt(len);
		out.writeInt(code);
		out.writeLong(playerId);
	}

	public byte[] toByteArray() {
		return bytes;
	}

	public short calcChecksum(byte[] data) {
		int val = 0x77;
		int i = 6;
		int size = data.length;
		while (i < size) {
			val += (data[i++] & 0xFF);
		}
		return (short) (val & 0x7F7F);
	}

	public String headerToStr() {
		StringBuilder sb = new StringBuilder();
		sb.append("playerId : ").append(playerId);
		sb.append(", code : ").append(Integer.toHexString(code));
		sb.append(", len : ").append(len);
		return sb.toString();
	}

	public String detailToStr() {
		if (bytes == null) {
			return null;
		}
		StringBuilder sb = new StringBuilder();
		for (byte b : bytes) {
			sb.append(b + ", ");
		}
		return headerToStr() + ", content : [" + sb.toString() + "]";
	}

	public byte getOpCode() {
		return opCode;
	}

	public void setOpCode(byte opCode) {
		this.opCode = opCode;
	}

	public Object getMyMsg() {
		return myMsg;
	}

	public void setMyMsg(Object myMsg) {
		this.myMsg = myMsg;
	}

	public int getByteLength() {
		return byteLength;
	}

	public void setByteLength(int byteLength) {
		this.byteLength = byteLength;
	}

	@Override
	public PBPacket clone() {
		PBPacket clone = null;
		try {
			clone = (PBPacket) super.clone();
			clone.setMessage(message);
			return clone;
		} catch (CloneNotSupportedException e) {
			LogUtil.COMMON.error("异常错误", e);
			return null;
		}
	}

	@Override
	public String toString() {
		return "PBMessage{code=" + code + ", playerId=" + playerId + "}";
	}
}
